package com.zjj.distributed.zk.curator;

import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author zhanglei.zjj
 * @description Zookeeper Curator客户端使用
 * @date 2023/6/19 21:46
 */
@Slf4j
public class CuratorDemo {
    private final static String CLUSTER_CONNECT_STR = "192.168.200.129:2181";
    static CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
            .connectString(CLUSTER_CONNECT_STR)
            .sessionTimeoutMs(4000)
            .retryPolicy(new ExponentialBackoffRetry(1000, 3)).
            namespace("").build();

    static {
        //启动客户端
        curatorFramework.start();
    }

    /**
     * 创建节点
     *
     * @throws Exception
     */
    @Test
    public void testCreate() throws Exception {
        String forPath = curatorFramework
                .create()
                .creatingParentsIfNeeded()
                // protection 模式，防止由于异常原因，导致僵尸节点
                .withProtection()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .forPath("/curator-node", "some-data".getBytes());
        log.info("curator create node :{}  successfully.", forPath);

    }

    /**
     * 一次性创建带层级结构的节点
     *
     * @throws Exception
     */
    @Test
    public void testCreateWithParent() throws Exception {
        String pathWithParent = "/node-parent/sub-node-1";
        String path = curatorFramework.create().creatingParentsIfNeeded().forPath(pathWithParent);
        log.info("curator create node :{}  successfully.", path);
    }

    /**
     * 获取数据
     *
     * @throws Exception
     */
    @Test
    public void testGetData() throws Exception {
        byte[] bytes = curatorFramework.getData().forPath("/curator-node");
        log.info("get data from  node :{}  successfully.", new String(bytes));
    }

    /**
     * 更新节点
     *
     * @throws Exception
     */
    @Test
    public void testSetData() throws Exception {
        curatorFramework.setData().forPath("/curator-node", "changed!".getBytes());
        byte[] bytes = curatorFramework.getData().forPath("/curator-node");
        log.info("get data from  node /curator-node :{}  successfully.", new String(bytes));
    }

    /**
     * 删除节点
     *
     * @throws Exception
     */
    @Test
    public void testDelete() throws Exception {
        String pathWithParent = "/node-parent";
        curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPath(pathWithParent);
    }

    @Test
    public void testAsync() throws Exception {
        curatorFramework.getData().inBackground((item1, item2) -> {
            log.info(" background: {}", item2);
        }).forPath("/curator-node");

        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

    @Test
    public void testAsyncSpecificThreadPool() throws Exception {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        curatorFramework.getData().inBackground((item1, item2) -> {
            log.info(" background: {}", item2);
        }, executorService).forPath("/curator-node");

        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

    public static void main(String[] args) throws Exception {
        //构建客户端实例
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                .connectString(CLUSTER_CONNECT_STR)
                .sessionTimeoutMs(4000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3)).
                namespace("").build();
        //启动客户端
        curatorFramework.start();
        Stat stat = new Stat();
        //查询节点数据
        byte[] bytes = curatorFramework.getData().storingStatIn(stat)
                .forPath("/user");
        System.out.println(new String(bytes));

        curatorFramework.close();
    }
}
